package demoMod.moduploader.core;

import com.badlogic.gdx.ApplicationListener;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Input;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.codedisaster.steamworks.SteamAPI;
import com.codedisaster.steamworks.SteamApps;
import com.codedisaster.steamworks.SteamException;
import com.codedisaster.steamworks.SteamID;
import demoMod.gdxform.abstracts.Container;
import demoMod.gdxform.core.FormManager;
import demoMod.gdxform.helpers.FontHelper;
import demoMod.gdxform.interfaces.Element;
import demoMod.gdxform.ui.*;
import demoMod.moduploader.fonts.FontKeys;
import demoMod.moduploader.interfaces.Refreshable;
import demoMod.moduploader.interfaces.ReloadStringsSubscriber;
import demoMod.moduploader.localization.LocalizedStrings;
import demoMod.moduploader.model.ModInfo;
import demoMod.moduploader.model.ModUploadItem;
import demoMod.moduploader.ui.*;
import demoMod.moduploader.utils.Preferences;
import demoMod.moduploader.utils.SteamTicker;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.lwjgl.opengl.Display;

import java.awt.*;
import java.io.*;
import java.lang.management.ManagementFactory;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

public class MainWindow implements ApplicationListener, ReloadStringsSubscriber {
    private SpriteBatch sb;
    private FormManager formManager;
    private static final Logger log = LogManager.getLogger(MainWindow.class);
    private String modCollectionPath;
    public static final Color steamBgColor = new Color(0.11373F, 0.15294F, 0.21569F, 1);
    public static MainWindow inst;

    @Override
    public void create() {
        Preferences.load();
        int[] resolution = Preferences.getPreferences().getResolution();
        if (resolution != null) {
            if (resolution[0] != Gdx.graphics.getWidth() || resolution[1] != Gdx.graphics.getHeight()) {
                Gdx.graphics.setWindowedMode(resolution[0], resolution[1]);
            }
        }
        String name = ManagementFactory.getRuntimeMXBean().getName();
        String pid = name.split("@")[0];
        log.info("pid is: " + pid);

        sb = new SpriteBatch();
        FontKeys.initialize();
        LocalizedStrings.reloadStrings();
        LocalizedStrings.subscribe(this);
        formManager = FormManager.getInstance();
        formManager.addContainer(new ModListPane());
        loadMenuBar();

        inst = this;
        if (Preferences.getPreferences().getLastOpenPath() != null) {
            setModCollectionPath(Preferences.getPreferences().getLastOpenPath());
            Display.setTitle("STS Mod Uploader - " + modCollectionPath);
            ((ModListPane) FormManager.getInstance().getContainerById(ModListPane.ID)).refresh();
        }
        writeSteamAppIDFile();
        List<String> errorMsg = LocalizedStrings.getStrings("ErrorMsg");
        try {
            SteamAPI.loadLibraries();
            if (SteamAPI.init()) {
                SteamApps steamApps = new SteamApps();

                SteamID id = steamApps.getAppOwner();

                int accountId = id.getAccountID();
                log.info("ACCOUNT ID: " + accountId);
                Thread thread = new Thread(new SteamTicker());
                thread.setName("SteamTicker");
                thread.setDaemon(true);
                thread.start();
            } else {
                log.error("Steam API failed to initialize correctly.");
                new MessageBox("", errorMsg.get(5), FontHelper.getFont(FontKeys.SIM_HEI_14)).setConfirmCallback(() -> Gdx.app.exit());
            }
        } catch (SteamException ex) {
            log.error(ex.getMessage(), ex);
            new MessageBox("", errorMsg.get(6), FontHelper.getFont(FontKeys.SIM_HEI_14)).setConfirmCallback(() -> Gdx.app.exit());
        }

        log.info("Application started!");
    }

    private void writeSteamAppIDFile() {
        File f = new File("steam_appid.txt");
        if (!f.exists()) {
            log.info("The file '" + f.getPath() + "' does not exist. Creating it...");
            try {
                Writer writer = new BufferedWriter(new OutputStreamWriter(Files.newOutputStream(Paths.get(f.getPath())), StandardCharsets.UTF_8));
                try {
                    writer.write(Integer.toString(646570));
                    writer.close();
                } catch (Throwable throwable) {
                    try {
                        writer.close();
                    } catch (Throwable throwable1) {
                        throwable.addSuppressed(throwable1);
                    }
                    throw throwable;
                }
            } catch (IOException e) {
                log.error(e.getMessage(), e);
            }
        } else {
            log.info("The file '" + f.getPath() + "' exists. Not creating it...");
        }
    }

    private void loadMenuBar() {
        GMenuBar menuBar = new GMenuBar();
        menuBar.setId("MainMenuBar");
        menuBar.setBackground(new Color(0.09412F, 0.11373F, 0.1451F, 1));
        menuBar.setHeight(22.0F);
        List<String> menuList = LocalizedStrings.getStrings("MainMenu");
        List<String> fileSelectWindowStrings = LocalizedStrings.getStrings("FileSelectWindow");
        List<String> errorMsg = LocalizedStrings.getStrings("ErrorMsg");
        GMenuBar.GMenuBarItem fileMenu = new GMenuBar.GMenuBarItem(48, menuBar.getHeight(), menuList.get(0), FontHelper.getFont(FontKeys.SIM_HEI_14)) {
            @Override
            public boolean isHotKeyPressed() {
                return Gdx.input.isKeyPressed(Input.Keys.F);
            }
        };

        fileMenu.setSubMenu(() -> {
            GMenuList fileMenuList = new GMenuList();
            fileMenuList.setWidth(300.0F);

            List<String> fileMenuStrings = LocalizedStrings.getStrings("FileMenu");
            GMenuItem openCollection = new GMenuItem(300.0F, fileMenuList.getMenuItemHeight(), fileMenuStrings.get(0) + "...", FontHelper.getFont(FontKeys.SIM_HEI_14)) {
                @Override
                public void onClick() {
                    GFileSelectWindow fileSelectWindow = new GFileSelectWindow(FontHelper.getFont(FontKeys.SIM_HEI_14));
                    fileSelectWindow.setTitle(fileMenuStrings.get(0));
                    fileSelectWindow.setConfirmText(fileSelectWindowStrings.get(0));
                    fileSelectWindow.setCancelText(fileSelectWindowStrings.get(1));
                    fileSelectWindow.setBackText(fileSelectWindowStrings.get(2));
                    fileSelectWindow.setFileFilter(File::isDirectory);
                    String path = Preferences.getPreferences().getLastOpenPath() == null ? new File("").getAbsolutePath() : Preferences.getPreferences().getLastOpenPath();
                    fileSelectWindow.setPath(path);
                    fileSelectWindow.setConfirmCallback((selectedPath, selectedFiles) -> {
                        File testFile = new File(selectedPath);
                        String folderPath;
                        if (testFile.isDirectory()) {
                            folderPath = testFile.getAbsolutePath();
                        } else {
                            folderPath = testFile.getParent();
                        }
                        setModCollectionPath(selectedPath);
                        Display.setTitle("STS Mod Uploader - " + folderPath);
                        Preferences.getPreferences().setLastOpenPath(folderPath);
                        Preferences.save();
                        ((ModListPane) FormManager.getInstance().getContainerById(ModListPane.ID)).refresh();
                    });
                }
            };

            GMenuItem newUploadFolder = new GMenuItem(300.0F, fileMenuList.getMenuItemHeight(), fileMenuStrings.get(1) + "...", FontHelper.getFont(FontKeys.SIM_HEI_14)) {
                @Override
                public void onClick() {
                    TextInputWindow textInputWindow = new TextInputWindow(fileMenuStrings.get(1), "", FontHelper.getFont(FontKeys.SIM_HEI_14));
                    textInputWindow.setCharFilter("[a-zA-Z0-9,.;'\\[\\]{}\\s`~\\-=!@#$%^&()_+]");
                    textInputWindow.setConfirmCallback(folderName -> {
                        File folder = new File(modCollectionPath + File.separator + folderName);
                        if (!folder.exists()) {
                            if (folder.mkdir()) {
                                File configFile = new File(folder, "config.json");
                                File content = new File(folder, "content");
                                File modCover = new File(folder, "image.jpg");
                                ModUploadItem modUploadItem = new ModUploadItem();
                                modUploadItem.setModConfigFile(configFile);
                                modUploadItem.setModImage(modCover);
                                modUploadItem.setModContentFolder(content);
                                content.mkdir();

                                ModInfo modInfo = new ModInfo();
                                modInfo.title = folderName;

                                modUploadItem.saveConfigFile(modInfo);
                                try (InputStream imageInStream = Gdx.files.internal("templates/image.jpg").read();
                                     OutputStream imageOutStream = Files.newOutputStream(modCover.toPath())) {
                                    byte[] buf = new byte[4096];
                                    int len;
                                    while ((len = imageInStream.read(buf)) > 0) {
                                        imageOutStream.write(buf, 0, len);
                                    }
                                } catch (Exception e) {
                                    new MessageBox("", errorMsg.get(1), FontHelper.getFont(FontKeys.SIM_HEI_14));
                                    return;
                                }
                                new MessageBox("", errorMsg.get(0), FontHelper.getFont(FontKeys.SIM_HEI_14)).setConfirmCallback(() -> refresh());
                            } else {
                                new MessageBox("", errorMsg.get(1), FontHelper.getFont(FontKeys.SIM_HEI_14));
                            }
                        } else {
                            new MessageBox("", errorMsg.get(2), FontHelper.getFont(FontKeys.SIM_HEI_14));
                        }
                    });
                }
            };
            newUploadFolder.setEnabled(modCollectionPath != null);
            GMenuItem openCollectionInExplorer = new GMenuItem(300.0F, fileMenuList.getMenuItemHeight(), fileMenuStrings.get(2), FontHelper.getFont(FontKeys.SIM_HEI_14)) {
                @Override
                public void onClick() {
                    File file = new File(modCollectionPath);
                    if (!Desktop.isDesktopSupported()) {
                        new MessageBox("", errorMsg.get(3), FontHelper.getFont(FontKeys.SIM_HEI_14));
                        return;
                    }

                    Desktop desktop = Desktop.getDesktop();

                    try {
                        desktop.open(file);
                    } catch (Exception e) {
                        new MessageBox("", errorMsg.get(4), FontHelper.getFont(FontKeys.SIM_HEI_14));
                    }
                }
            };
            openCollectionInExplorer.setEnabled(modCollectionPath != null);
            openCollectionInExplorer.setSplitLine(false);

            fileMenuList.addElement(openCollection);
            fileMenuList.addElement(newUploadFolder);
            fileMenuList.addElement(openCollectionInExplorer);
            return fileMenuList;
        });

        GMenuBar.GMenuBarItem optionsMenu = new GMenuBar.GMenuBarItem(48, menuBar.getHeight(), menuList.get(1), FontHelper.getFont(FontKeys.SIM_HEI_14)) {
            @Override
            public boolean isHotKeyPressed() {
                return Gdx.input.isKeyPressed(Input.Keys.O);
            }
        };

        optionsMenu.setSubMenu(() -> {
            GMenuList optionMenuList = new GMenuList();
            optionMenuList.setWidth(300.0F);

            List<String> optionMenuStrings = LocalizedStrings.getStrings("OptionMenu");
            GMenuItem windowResolution = new GMenuItem(300.0F, optionMenuList.getMenuItemHeight(), optionMenuStrings.get(0) + "...", FontHelper.getFont(FontKeys.SIM_HEI_14)) {
                @Override
                public void onClick() {
                    List<String> screenSize = new ArrayList<>();
                    screenSize.add("800 * 600");
                    screenSize.add("1024 * 768");
                    screenSize.add("1280 * 960");
                    screenSize.add("1440 * 1080");
                    screenSize.add("2880 * 2160");
                    int index;
                    switch (Gdx.graphics.getWidth() * 1000 + Gdx.graphics.getHeight()) {
                        case 800600:
                        default:
                            index = 0;
                            break;
                        case 1024768:
                            index = 1;
                            break;
                        case 1280960:
                            index = 2;
                            break;
                        case 1441080:
                            index = 3;
                            break;
                        case 2882160:
                            index = 4;
                            break;
                    }
                    OptionWindow optionWindow = new OptionWindow(optionMenuStrings.get(0), screenSize, FontHelper.getFont(FontKeys.SIM_HEI_14), index);
                    optionWindow.setConfirmCallback(i -> {
                        int[] res = new int[2];
                        switch (i) {
                            case 0:
                                res[0] = 800;
                                res[1] = 600;
                                break;
                            case 1:
                                res[0] = 1024;
                                res[1] = 768;
                                break;
                            case 2:
                                res[0] = 1280;
                                res[1] = 960;
                                break;
                            case 3:
                                res[0] = 1440;
                                res[1] = 1080;
                                break;
                            case 4:
                                res[0] = 2880;
                                res[1] = 2160;
                                break;
                        }
                        Preferences.getPreferences().setResolution(res);
                        Preferences.save();
                        new MessageBox("", optionMenuStrings.get(5), FontHelper.getFont(FontKeys.SIM_HEI_14));
                    });
                }
            };

            GMenuItem language = new GMenuItem(300.0F, optionMenuList.getMenuItemHeight(), optionMenuStrings.get(1) + "...", FontHelper.getFont(FontKeys.SIM_HEI_14)) {
                @Override
                public void onClick() {
                    List<String> languages = new ArrayList<>();
                    languages.add(optionMenuStrings.get(3));
                    languages.add(optionMenuStrings.get(4));
                    int index = 0;
                    switch (Preferences.getPreferences().getLanguage()) {
                        case "zhs":
                        default:
                            break;
                        case "eng":
                            index = 1;
                            break;
                    }
                    OptionWindow optionWindow = new OptionWindow(optionMenuStrings.get(1), languages, FontHelper.getFont(FontKeys.SIM_HEI_14), index);
                    optionWindow.setConfirmCallback(i -> {
                        switch (i) {
                            case 0:
                            default:
                                Preferences.getPreferences().setLanguage("zhs");
                                break;
                            case 1:
                                Preferences.getPreferences().setLanguage("eng");
                                break;
                        }
                        Preferences.save();
                        LocalizedStrings.reloadStrings();
                    });
                }
            };

            GMenuItem about = new GMenuItem(300.0F, optionMenuList.getMenuItemHeight(), optionMenuStrings.get(2) + "...", FontHelper.getFont(FontKeys.SIM_HEI_14)) {
                @Override
                public void onClick() {
                    new AboutWindow();
                }
            };
            about.setSplitLine(false);

            optionMenuList.addElement(windowResolution);
            optionMenuList.addElement(language);
            optionMenuList.addElement(about);

            return optionMenuList;
        });

        menuBar.addElement(fileMenu);
        menuBar.addElement(optionsMenu);
        formManager.addContainer(menuBar);
    }

    public String getModCollectionPath() {
        return modCollectionPath;
    }

    public void setModCollectionPath(String modCollectionPath) {
        this.modCollectionPath = modCollectionPath;
        if (this.modCollectionPath.endsWith(File.separator)) {
            this.modCollectionPath = this.modCollectionPath.substring(0, this.modCollectionPath.length() - 1);
        }
    }

    @Override
    public void resize(int width, int height) {

    }

    @Override
    public void render() {
        Gdx.gl20.glClearColor(0.11373F, 0.15294F, 0.21569F, 1);
        Gdx.gl20.glClear(GL20.GL_COLOR_BUFFER_BIT);
        formManager.update();
        sb.begin();
        formManager.render(sb);
        sb.end();
    }

    @Override
    public void pause() {
        formManager.pause();
    }

    @Override
    public void resume() {
        formManager.resume();
        refresh();
    }

    private void refresh() {
        for (Container<? extends Element> container : FormManager.getInstance().getContainerList().stream().filter(container -> container instanceof Refreshable).collect(Collectors.toList())) {
            ((Refreshable) container).refresh();
        }
    }

    @Override
    public void dispose() {
        formManager.dispose();
        sb.dispose();
    }

    @Override
    public void onReloadStrings() {
        loadMenuBar();
        List<String> textFieldStrings = LocalizedStrings.getStrings("TextField");
        GTextField.cutText = textFieldStrings.get(0);
        GTextField.copyText = textFieldStrings.get(1);
        GTextField.pasteText = textFieldStrings.get(2);
        GTextField.selectAllText = textFieldStrings.get(3);
    }
}
